/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/02/18
* File: polyhedron.h
**/

#pragma once

#include "vector3.h"

namespace HY
{

class BoundingBox;
class Frustum;
class Matrix3;
class Matrix3x4;
class Plane;

/// A convex volume built from polygon faces.
class Polyhedron
{
public:
	/// Construct empty.
	Polyhedron()
	{
	}

	/// Copy-construct from another polyhedron.
	Polyhedron(const Polyhedron& polyhedron) :
	faces_(polyhedron.faces_)
	{
	}

	/// Construct from a list of faces.
	Polyhedron(const std::vector<std::vector<Vector3> >& faces) :
	faces_(faces)
	{
	}

	/// Construct from a bounding box.
	Polyhedron(const BoundingBox& box)
	{
		Define(box);
	}

	/// Construct from a frustum.
	Polyhedron(const Frustum& frustum)
	{
		Define(frustum);
	}

	/// Destruct.
	~Polyhedron();

	/// Define from a bounding box.
	void Define(const BoundingBox& box);
	/// Define from a frustum.
	void Define(const Frustum& frustum);
	/// Add a triangle face.
	void AddFace(const Vector3& v0, const Vector3& v1, const Vector3& v2);
	/// Add a quadrilateral face.
	void AddFace(const Vector3& v0, const Vector3& v1, const Vector3& v2, const Vector3& v3);
	/// Add an arbitrary face.
	void AddFace(const std::vector<Vector3>& face);
	/// Clip with a plane.
	void Clip(const Plane& plane);
	/// Clip with a bounding box.
	void Clip(const BoundingBox& box);
	/// Clip with a frustum.
	void Clip(const Frustum& box);
	/// Clear all faces.
	void Clear();
	/// Transform with a 3x3 matrix.
	void Transform(const Matrix3& transform);
	/// Transform with a 3x4 matrix.
	void Transform(const Matrix3x4& transform);

	/// Return transformed with a 3x3 matrix.
	Polyhedron Transformed(const Matrix3& transform) const;
	/// Return transformed with a 3x4 matrix.
	Polyhedron Transformed(const Matrix3x4& transform) const;
	/// Return whether is empty.
	bool empty() const { return faces_.empty(); }

	/// Polygon faces.
	std::vector<std::vector<Vector3> > faces_;

private:
	/// Set a triangle face by index.
	void SetFace(unsigned index, const Vector3& v0, const Vector3& v1, const Vector3& v2);
	/// Set a quadrilateral face by index.
	void SetFace(unsigned index, const Vector3& v0, const Vector3& v1, const Vector3& v2, const Vector3& v3);
	/// Internal vector for clipped vertices.
	std::vector<Vector3> clippedVertices_;
	/// Internal vector for the new face being constructed.
	std::vector<Vector3> outFace_;
};

}